#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <getopt.h>
#include "matrix.h"
#include "estimar.h"

#define MEDIA 0
#define DESVIACION_ESTANDAR 1
#define MEDIANA 2

#define NUM_CONVERT_FUNCTION strtod

typedef int bool;
#define false (0)
#define true (1)

estimador_t letter_to_function( char character) {
	if (character == 'm') return estimador_media;
	if (character == 'v') return estimador_varianza;
	
	return 0;
}

void help() {
printf(
"Usage:\n"
"	tp1 -h				Display this message and exit.\n"
"	tp1 -V				Display version.\n"
"	tp1 -i --infile			Input file. - stands for stdin.\n"
"	tp1 -o --outfile		Output file. - stands for stdout.\n"
"	tp1 -c --command		One of (m,v).\n"
);
	
	
}

void version() {
printf("TP1 v1.1\n");
	
}

int main(int argc, char* argv[] )  {
	const char* input_file_path = "/dev/stdin";
	const char* output_file_path = "/dev/stdout";
	char* next_token;
	char* pch;
	char* last_token;
	int acumulado = false;
	
	int buffer_position = 0;
	char buffer_acumulado[64];

	int len;

	estimador_t function = 0;
	
	// calculo de media
	NUMTYPE sumatoria = 0;

	// calculo de desviacion estandar
	NUMTYPE sumatoria_de_cuadrados = 0;
	
	// comun
	int cantidad = 0;
	
        struct option long_options[] = {
            {"infile", 1, 0, 0},
            {"outfile", 1, 0, 0},
            {"command", 1, 0, 0},
            {"help", 0, 0, 0},
            {0, 0, 0, 0}
         };
	 
	 while (1) {
		 int option_index = 0;
		 int c;
		 
		 c = getopt_long(argc, argv, "i:o:c:hV", long_options, &option_index);
		 if (c == -1) break;
		 
		 switch (c) {
			case 0:
				switch(option_index) {
					case 0:
						input_file_path = optarg;
						break;
					case 1:
						output_file_path = optarg;
						break;
					case 2:
						function = letter_to_function( optarg[0] );
						if (function == 0) {
							fprintf(stderr, "Invalid function %s\n", optarg );
							help();
							return 1;
						}
						break;
					case 3:
						help();
						return 0;
				}
				break;
			case 'i':
				input_file_path = optarg;
				break;
			case 'o':
				output_file_path = optarg;
				break;
			case 'c':
				function = letter_to_function( optarg[0] );
				if (function == 0) {
					fprintf(stderr, "Invalid function %s\n", optarg );
					help();
					return 1;
				}
				break;
			case 'h':
				help();
				return 0;
			case 'V':
				version();
				return 0;
		 }
	 }
	
	if (function == 0) {
		fprintf(stderr, "Function not specified\n", optarg );
		help();
		return 1;
	}
	FILE* input_file;
	FILE* output_file;
	
	output_file = fopen(output_file_path, "w");
	 
	if (!output_file) {
		fprintf(stderr,"Cannot open %s for write\n", output_file_path);
		return 1;
	}
	 
	input_file = fopen(input_file_path, "r");
	 
	if (!input_file) {
		fprintf(stderr,"Cannot open %s for read\n", input_file_path);
		return 1;
	}
	
	Matrix* matrix = createMatrix();
	
	int i=0;
	int j=0;
	
	while (!feof(input_file)) {

		int caracter;
		
		caracter = fgetc(input_file);
		
		if (caracter == '\n' || caracter == ' ' || caracter == -1 || caracter == ';') {
			
			if (buffer_position > 0) {
				
				NUMTYPE num;
				
				buffer_acumulado[buffer_position] = '\0';
				buffer_position = 0;

				char* endptr;
				num = NUM_CONVERT_FUNCTION(buffer_acumulado, &endptr);
				
				if (endptr == buffer_acumulado) {
					
					destroyMatrix(matrix);
					
					fclose(output_file);
					fclose(input_file);

					fprintf(stderr, "Error: dato no numerico ingresado '%s'\n", buffer_acumulado);
					return 1;
				}

				*indexMatrix(matrix,i,j) = num;
				
				if (caracter == ';') {
					j=0;
					i++;
				} else {
					j++;
				}
				
			}
		} else {
			buffer_acumulado[buffer_position] = caracter;
			buffer_position++;
		}
		
		if (caracter == -1) {
			break;
		}
	}
	
	if ( j != matrix->size  || i != matrix->size - 1) {
		destroyMatrix(matrix);
		
		fclose(output_file);
		fclose(input_file);
		
		fprintf(stderr, "Error: la matriz no es cuadrada o esta incompleta\n");
		return 1;
	}

	NUMTYPE resultado[matrix->size];
	estimar( matrix->data, matrix->size, resultado,  function);

	for (i=0; i<matrix->size; i++) {
		printf("%f", resultado[i]);
		if (i+1 < matrix->size) printf(" ");
	}	
	
	printf("\n");
	
	destroyMatrix(matrix);
	
	fclose(output_file);
	fclose(input_file);
	return 0;
}

